package streaming;

import java.io.FileOutputStream;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.TreeSet;

import simulation.Config;
import simulation.FileLog;
import simulation.FullStatistics;
import simulation.Logs;
import simulation.PeriodicStats;
import simulation.Simulator;
import simulation.Statistics;
import simulation.Util;

public class Chainsaw {

	Overlay overlay;
	PeriodicStats periodicStats = new PeriodicStats();
	String filename;
	static Date startSimulationDate;
	static Date endSimulationDate;

	// --------------------
	// CONSTRUTOR
	// --------------------
	
	public Chainsaw() {
	}

	// --------------------
	// MAIN
	// --------------------

	public static void main(String[] args) throws IOException {

		System.out.println("## ==============================================");
		System.out.println("## Starting Sim. V.1.0.4 -- " + Util.sysdate2() );
		System.out.println("## ==============================================");

		if ( StreamingConfig.GENERATE_EXTRA_LOGS == true  &&  StreamingConfig.CLEAR_EXTRA_LOGS == true ) {
			System.out.println("## Erasing logfiles...");

			// erasing logfiles
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/log.txt",                            false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_DESCR_logfiles.txt",           false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_configuracao.txt",             false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_chunks-env-fireflies.txt",     false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_chunks-env-mod-comp.txt",      false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_chunks_overhead.txt",          false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_total_peers_poluidos.txt",     false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_total_peers_poluidos_CID.txt", false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_total_peers_poluidos_SEG.txt", false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_blacklist_CID.txt",            false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_neighbors.txt",                false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_chunks_to_compare.txt",        false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_peers_creation.txt",           false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/DADOS_diagnosis.txt",                false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/log_poluted_peers.txt",              false);
			new FileWriter(System.getProperty("user.dir") + "/FinalStats/log_temp.txt",                       false);
		}

		FileLog.getInstance().saveFinalStatsInFile("FinalStats", "DADOS_DESCR_logfiles", Util.rpad( "DADOS_total_peers_poluidos_SEG.txt", 50 ) + "--> ##  [cfg]  id_sim  segundo  qt_peers_pol  qt_chunks_pol  qt_chunks_orig  qt_total_chunks  pct_pol"     +"\n" );
		FileLog.getInstance().saveFinalStatsInFile("FinalStats", "DADOS_DESCR_logfiles", Util.rpad( "DADOS_total_peers_poluidos.txt"    , 50 ) + "--> ##  [cfg]  id_sim  avg_pol_peers     total_pol_chunks  total_chunks  pct_pol     total_pol_chunks_aft30s  total_chunks_aft30s  pct_pol_aft30s"     +"\n" );
		FileLog.getInstance().saveFinalStatsInFile("FinalStats", "DADOS_DESCR_logfiles", Util.rpad( "DADOS_blacklist_CID.txt"           , 50 ) + "--> ##  [cfg]  id_sim  Peer  cid  #viz  #vizPoluidores  #sim-time  #peers-na-blacklist  #polluters-na-bl  ??  hit-acertou?  [blacklist]"     +"\n" );

		
		Logs.cleanUpLogFile();

		int maliciousPeersRatio = 0; // ratio of malicious peers (1(0%), 2(5%), 3(10%), 4(15%), 5(20%), 6(25%))
		int endMaliciousPeersRatio = 6; // end of ratio. Used to finish the first for loop below
		boolean ratioMaliciousPeers = false;
		// Integer param_numberOfPeers = new Integer(0);

		if (args.length != 0) {
			int numArgs = 0;
			while (numArgs < args.length) {
				// Argument '-i' -> initial simulation counter to be written in files
				if (args[numArgs].equalsIgnoreCase("-i")) {

					if (numArgs + 1 < args.length) { // Check if can access the next position, i.e., if it is not null
						try {
							StreamingConfig.RUN_SIMULATIONS_VARYING_ALL_PARAMETERES = true;
							Config.START_COUNTER_SIMULATIONS = Integer.parseInt(args[numArgs + 1]);
							Config.END_COUNTER_SIMULATIONS = Config.START_COUNTER_SIMULATIONS
									+ Config.NUMBER_OF_SIMULATIONS;
							numArgs++; // step one argument (the value of the
										// argument)
						} catch (NumberFormatException nfe) {
							System.out
									.println("ERROR: Value of argument -i must be a number.");
						}
					} else {
						System.out.println("ERROR: Argument -i needs a value.");
						System.exit(1);
					}
				}
				// If the ratio of malicious peers were set...
				if (args[numArgs].equalsIgnoreCase("-m")) {
					ratioMaliciousPeers = true;

					if (numArgs + 1 < args.length) { // Check if can access the next position, i.e., if it is not null
						try {
							StreamingConfig.RUN_SIMULATIONS_VARYING_ALL_PARAMETERES = true;
							maliciousPeersRatio = new Integer(args[numArgs + 1]);
							endMaliciousPeersRatio = maliciousPeersRatio;
							numArgs++; // step one argument (the value of the
										// argument)
						} catch (NumberFormatException nfe) {
							System.out.println("ERROR: Value of argument -m must be a number.");
						}
					} else {
						System.out.println("ERROR: Argument -m needs a value.");
						System.exit(1);
					}
				}

				numArgs++;
			}
		}

		
		// LOG - MALICIOUS PEER RATIO
		
		if (!ratioMaliciousPeers) {
			System.out.println("## [PARAM] no malicious peers.");
		} else {
			System.out.println("## [PARAM] malicious peers configured. Ration = "	+ maliciousPeersRatio);
		}

		

		// -----------------------------------
		// ALL PARAMETERS / CONFIGURATIONS 
		// -----------------------------------
		
		for (int numSim = Config.START_COUNTER_SIMULATIONS; numSim < Config.END_COUNTER_SIMULATIONS; numSim++) {

			if (StreamingConfig.RUN_SIMULATIONS_VARYING_ALL_PARAMETERES == false) {

				// ------------------------------------------------
				// ONLY ONE SIMULATION
				// ------------------------------------------------

				System.out.println( "## Executing only one simulation. NumSim=" + numSim );
				startSimulation(numSim);

			} 
			else {

				// ------------------------------------------------
				// SIMULATIOS FOR ALL PARAMETERS / CONFIGURATIONS 
				// ------------------------------------------------

				for (; maliciousPeersRatio <= endMaliciousPeersRatio; maliciousPeersRatio++) {

					switch (maliciousPeersRatio) {
					case 1: // no malicious peers;
						StreamingConfig.SIMULATION_WITH_ATTACKERS = false;
						StreamingConfig.ATTACKERS_RATIO = 0.0;
						break;
					case 2: // 5% of malicious peers;
						StreamingConfig.ATTACKERS_RATIO = 0.05;
						break;
					case 3: // 10% of malicious peers;
						StreamingConfig.ATTACKERS_RATIO = 0.1;
						break;
					case 4: // 15% of malicious peers;
						StreamingConfig.ATTACKERS_RATIO = 0.15;
						break;
					case 5: // 20% of malicious peers;
						StreamingConfig.ATTACKERS_RATIO = 0.20;
						break;
					case 6: // 25% of malicious peers;
						StreamingConfig.ATTACKERS_RATIO = 0.25;
						break;
					}

					// Number of peers
//RPZ				for (int numberOfPeers = 1; numberOfPeers <= 3; numberOfPeers++) {
					for (int numberOfPeers = 1; numberOfPeers <= 2; numberOfPeers++) {
						switch (numberOfPeers) {
						case 1: // 200 initial peers
							StreamingConfig.INITIAL_HOSTS_NUMBER = 200;
							break;
						case 2: // 500 initial peers
							StreamingConfig.INITIAL_HOSTS_NUMBER = 500;
							break;
						case 3: // 1000 initial peers
							StreamingConfig.INITIAL_HOSTS_NUMBER = 1000;
							break;
						}

						// if ( param_numberOfPeers > 0 && param_numberOfPeers != StreamingConfig.INITIAL_HOSTS_NUMBER ) { continue; }

						// Type of churn to be used
						for (int churnType = 1; churnType <= 3; churnType++) {
							switch (churnType) {
							case 1: // without churn
								StreamingConfig.DYNAMIC_INSERTION_ON = false;
								StreamingConfig.DYNAMIC_REMOVAL_ON = false;
								break;
							case 2: // 50% of churn (half of the peers are
									// removed during the execution)
								StreamingConfig.DYNAMIC_INSERTION_ON = true;
								StreamingConfig.DYNAMIC_REMOVAL_ON = true;

								StreamingConfig.HOSTS_NUMBER_TO_INSERT_ON_DISTRIBUTION = (int) (StreamingConfig.INITIAL_HOSTS_NUMBER * 0.5);
								StreamingConfig.HOSTS_NUMBER_TO_REMOVE_ON_DISTRIBUTION = (int) (StreamingConfig.INITIAL_HOSTS_NUMBER * 0.5);
								break;
							case 3: // 100% of churn (100% of the peers are
									// removed during the execution)
								StreamingConfig.DYNAMIC_INSERTION_ON = true;
								StreamingConfig.DYNAMIC_REMOVAL_ON = true;

								StreamingConfig.HOSTS_NUMBER_TO_INSERT_ON_DISTRIBUTION = (int) StreamingConfig.INITIAL_HOSTS_NUMBER;
								StreamingConfig.HOSTS_NUMBER_TO_REMOVE_ON_DISTRIBUTION = (int) StreamingConfig.INITIAL_HOSTS_NUMBER;
								break;
							}

							// tracker monitorament interval
//RPZ						for (int monitoramentInterval = 1; monitoramentInterval <= 2; monitoramentInterval++) {
							for (int monitoramentInterval = 2; monitoramentInterval <= 2; monitoramentInterval++) {
								switch (monitoramentInterval) {
								case 1: // interval of monitorament = 1
									StreamingConfig.CHUNK_SELECTION_INTERVAL = 2.0;
									break;
								case 2: // interval of monitorament = 2
									StreamingConfig.CHUNK_SELECTION_INTERVAL = 15.0;
									break;
								}

								if (maliciousPeersRatio == 1) {
									String polluterType = "none";

									// Churn used
									String churnUsed = (churnType == 2) ? "comch50" : (churnType == 3) ? "comch100" : "semch";

									System.out.println("[" + StreamingConfig.ATTACKERS_RATIO + "," + polluterType + "," + churnUsed + "," + StreamingConfig.INITIAL_HOSTS_NUMBER + "," + (int) StreamingConfig.CHUNK_SELECTION_INTERVAL + "]");

									startSimulation(numSim);
								} 
								else { 
									// When the polluter ratio is greater than 0...

									// Set parameters for the type of malicious peer, but ONLY if there are malicious peers.
//RPZ								for (int typeMaliciousPeer = 1; typeMaliciousPeer <= 3; typeMaliciousPeer++) {
									for (int typeMaliciousPeer = 1; typeMaliciousPeer <= 1; typeMaliciousPeer++) {
										switch (typeMaliciousPeer) {
										case 1: // always pollute
											StreamingConfig.ATTACK_TYPE = 5;
											StreamingConfig.ALWAYS_POLLUTE = true;
											break;
										case 2: // pollutes randomly
											StreamingConfig.ATTACK_TYPE = 5;
											StreamingConfig.ALWAYS_POLLUTE = false;
											break;
										case 3: // omites
											StreamingConfig.ATTACK_TYPE = 3;
											break;
										}

										String polluterType;

										if (StreamingConfig.ATTACK_TYPE == 3) {
											polluterType = "omite";
										} 
										else {
											if (StreamingConfig.ALWAYS_POLLUTE) {
												polluterType = "sempre";
											} 
											else {
												polluterType = "aleat";
											}
										}
										String churnUsed = "semch";

										// Churn used
										if (StreamingConfig.DYNAMIC_INSERTION_ON) {
											churnUsed = "comch" + (100 * StreamingConfig.HOSTS_NUMBER_TO_INSERT_ON_DISTRIBUTION / StreamingConfig.INITIAL_HOSTS_NUMBER);
										}

										System.out.println(  "["+ StreamingConfig.ATTACKERS_RATIO+ ","+ polluterType+ ","+ churnUsed+ ","+ StreamingConfig.INITIAL_HOSTS_NUMBER+ ","+ (int) StreamingConfig.CHUNK_SELECTION_INTERVAL+ "]"  );
										
										startSimulation(numSim);
									}
								}
							}
						}
					}
				}
			}
		}

		// -----------------------------------

		
		System.out.println( "## ================" );
		System.out.println( "## END OF EXECUTION" );
		System.out.println( "## ================" );
	}

	// --------------------
	// MAIN (final)
	// --------------------


	
	public static void startSimulation(int numSim) {
		
		startSimulationDate = new Date();
		System.out.println("## [ini] --> startSimulation " +"["+Util.to_char(startSimulationDate)+"]");
		int simulacao = 0;
		// for (int aux = 1 ; aux <= 1 ; aux++){
		simulacao++;
		FileLog.openFile(simulacao + "");
		// Chainsaw.setConfigurations(aux);

		FileLog.getInstance(); // true means to append file
		FileLog.getInstance().appendStringResults( "chunks sent, chunks sent by CM, # of requests, # of U sets sent to tracker, polluted peers, mean of polluted peers in diagnosed chunks, % of polluted peers diagnosticated\n" );


		// GENERATING CONFIGURATION STRING
		Simulator.getInstance().generateConfigurationString(numSim);
		
		
		// -------------------
		// START OF SIMULATION
		// -------------------

		System.out.println("## -------------------");
		System.out.println("## START OF SIMULATION ---> " + Simulator.getInstance().strSimulationConfigCompl);
		System.out.println("## -------------------");


		Chainsaw chainsaw = new Chainsaw();
		chainsaw.overlay = Overlay.getInstance();

		Logs.printMessage("main", "## Starting Simulation Execution! NumSim=" + (numSim) + " " + Util.sysdate2() );
		System.out.println( "## Starting Simulation Execution! NumSim=" + (numSim) + " " + Util.sysdate2() );
		// System.out.println( "## -----------------" );

		// checks whether simulation will have or not attackers
		if (StreamingConfig.SIMULATION_WITH_ATTACKERS) {
			// Check if the attack type selected does exist
			if (StreamingConfig.ATTACK_TYPE >= 1 && StreamingConfig.ATTACK_TYPE <= 5) {
				chainsaw.experimentWithAttackers(StreamingConfig.ATTACK_TYPE, StreamingConfig.ATTACKERS_RATIO, numSim);
			} else {
				System.out.println("The attack type " + StreamingConfig.ATTACK_TYPE + " couldn't be found.");
				System.exit(1);
			}
		} else {
			chainsaw.experimentWithoutAttackers(numSim);
		}

		endSimulationDate = new Date();
		System.out.println("## [" + endSimulationDate + "] Simulation finished. Time spent on blacklist = " + Simulator.getInstance().msecs_blacklist);
		System.out.println("## Diff: "+ ((endSimulationDate.getTime() - startSimulationDate.getTime()) / 1000) / 60 + " minutes");

		// System.out.println( "## -----------------" );
		System.out.println( "## End of Simulation Execution! NumSim=" + (numSim) + " " + Util.sysdate2() );

		// -----------------
		// END OF SIMULATION
		// -----------------


		
		// ------------------------------------
		// PRINTING SUMMARY OF SIMULATION STATS
		// ------------------------------------

		System.out.println("## =============");
		System.out.println("## Summary Stats");
		System.out.println("## =============");
		
		Object[] hostsList = chainsaw.overlay.hosts.values().toArray();

		Arrays.sort(hostsList, chainsaw.new idComparator());

		int media = 0;
		for (int j = 0; j < hostsList.length; j++) {
			Host auxHost = (Host) hostsList[j];

			// //System.out.println("\n********** Host " + auxHost.getId() + " **********");
			Iterator iterator = auxHost.neighbors.keySet().iterator();
			Neighbor neighbor;

			if (Config.USE_COMPARATOR_MODULE) {
				// //System.out.print("Vizinhos: [");
				while (iterator.hasNext()) {
					neighbor = (Neighbor) auxHost.neighbors
							.get(iterator.next());
					// //System.out.print(neighbor.id + ",");
				}
				// //System.out.println("]\n");
				//
				// // Print comparator requests
				// for (RequestedPacket rp :
				// auxHost.comparatorModule.getMapRequestedChunks().values()){
				// System.out.print("Chunk " + rp.getCID() + ": [");
				// for (HostRequestedDiagnostic hrd :
				// rp.getHostsList().values()){
				// System.out.print(hrd.getHostId() + "(" + hrd.isAnswered()
				// +"),");
				// }
				// System.out.println("]");
				// }

				// Print U Sets
				// auxHost.comparatorModule.printUSets();
			}

			if (j > 0) {
				media += auxHost.downloadStats.sum();
				// //Logs.printMessage("main", "Host " + j + " recebeu " +
				// auxHost.downloadStats.sum());
			}
		}

		Integer pacotesGerados = (((SourceHost) chainsaw.overlay.getHost(0)).seqNo);
		Logs.printConfig((double) pacotesGerados, (double) Simulator.getInstance().getIntTotalChunksReceived() / (hostsList.length - 1));

		Logs.printMessage("summary", Simulator.getInstance().getIntMessagesSimpleSimulation() + " messages were sent between peers to transmite data.");

		Logs.printMessage("summary", Simulator.getInstance().getIntTotalChunksSent() + " chunks were sent by peers to transmite data.");
		Logs.printMessage("summary", Simulator.getInstance().getIntTotalChunksReceived() + " chunks were received by peers.");

		if (StreamingConfig.SIMULATION_WITH_ATTACKERS) {
			Logs.printMessage("summary", Simulator.getInstance().getIntOriginalChunksCounter() + " original chunks were received by peers.");
			Logs.printMessage("summary", Simulator.getInstance().getIntModifiedChunksCounter() + " modified chunks were sent by peers.");
		}

		if (Config.USE_COMPARATOR_MODULE) {
			chainsaw.printPollutedPeers();

			Logs.printMessage( "summary", Simulator.getInstance().getIntDiagnosticRequestMessages() + " request messages were transmited by comparator modules to do the system diagnostic.");
			Logs.printMessage( "summary", Simulator.getInstance().getIntDiagnosticResponseMessages() + " response messages were transmited by comparator modules to do the system diagnostic.");
			Logs.printMessage( "summary", (Simulator.getInstance().getIntDiagnosticRequestMessages() + Simulator.getInstance().getIntDiagnosticResponseMessages()) + " messages in total were transmited by comparator modules to do the system diagnostic.");
			//Tracker.getInstance().printTSet();
		}

		String results = Simulator.getInstance().getIntTotalChunksSent() + ",";      // number of chunks sent by peers
		results += Simulator.getInstance().getIntDiagnosticResponseMessages() + ","; // number of messages with chunks from CMs
		results += Simulator.getInstance().getIntDiagnosticRequestMessages() + ",";  // number of request messages
		results += Simulator.getInstance().getIntTotalUSetsSentTracker() + ",";      // number of U sets sent to tracker
		results += Simulator.getInstance().getIntModifiedChunksCounter() + ",";      // number of peers that received polluted chunks
		results += chainsaw.meanPollutedInDiagnosed() + ",";                         // mean of polluted peers with cids diagnosed
		results += chainsaw.diagnosticAccuracy() + "%\n";

		FileLog.getInstance().appendStringResults(results);

		
		
		// ----------------------------------------------
		// GENERATING LOG FILES
		// ----------------------------------------------

		System.out.println("## ==========================");
		System.out.println("## Generating Final Log Files");
		System.out.println("## ==========================");

		String strSimulationConfig = Simulator.getInstance().strSimulationConfig;
		String strSimulationConfigCompl = Simulator.getInstance().strSimulationConfigCompl;


		System.out.println("## gerando arquivos de dados/logs " + Util.sysdate2());
		
		
		// ----------------------------------------------
		// DADOS_configuracao.txt
		// ----------------------------------------------
		/* 0 */// - arquivo com as configuracoes da simulacao -->
				// DADOS_configuracao.txt (1 linha p/ cada simulacao, exemplo:
				// [5%,sempre,semch,200] #sim tempo_simulacao chunks_por_seg
				// tamanho_janela_disponibilidade tamanho_janela_interesse)
		String strConfigData = new String();

		strConfigData = strSimulationConfigCompl
				+ Config.TIME + " "
				+ StreamingConfig.MCASTRATE + " "
				+ StreamingConfig.MCASTWINDOWSIZE + " "
				+ StreamingConfig.MCASTINTERESTWINDOWSIZE + "\n";

		FileLog.getInstance().saveFinalStatsInFile("FinalStats","DADOS_configuracao", strConfigData);
		
		// ----------------------------------------------
		// DADOS_configuracao.txt
		// ----------------------------------------------
		// - qtde de chunks enviados (reply) normalmente pelo Fireflies (sem o MC) --> DADOS_chunks-env-fireflies.txt (1 linha p/ cada simulacao, exemplo: "[5%,sempre,semch,200,15] #sim qtde" )
		FileLog.getInstance().saveFinalStatsInFile( "FinalStats", "DADOS_chunks-env-fireflies", strSimulationConfigCompl + 
				+ Simulator.getInstance().getIntTotalChunksSent() + "\n");
		
		// ----------------------------------------------
		// DADOS_chunks-env-mod-comp.txt
		// ----------------------------------------------
		if (Config.USE_COMPARATOR_MODULE) {
			// - qtde de chunks enviados especificamente pelo MC (reply de um request do MC) --> DADOS_chunks-env-mod-comp.txt (1 linha p/ cada simulacao, exemplo: [5%,sempre,semch,200,15] #sim qtde )
			FileLog.getInstance().saveFinalStatsInFile( "FinalStats", "DADOS_chunks-env-mod-comp", strSimulationConfigCompl + 
				Simulator.getInstance().getIntDiagnosticResponseMessages() + "\n");
		}

		// ----------------------------------------------
		// DADOS_chunks_overhead.txt
		// ----------------------------------------------

		if (Config.USE_COMPARATOR_MODULE) {
			FileLog.getInstance().saveFinalStatsInFile( "FinalStats", "DADOS_chunks_overhead", strSimulationConfigCompl + 
				Simulator.getInstance().getIntTotalChunksSent() + " " +
				Simulator.getInstance().getIntDiagnosticResponseMessages() + " " +
				Util.to_char( (double)Simulator.getInstance().getIntDiagnosticResponseMessages() / (double)Simulator.getInstance().getIntTotalChunksSent() * (double)100  ,2) + 
				"\n");
		}
		else {
			FileLog.getInstance().saveFinalStatsInFile( "FinalStats", "DADOS_chunks_overhead", strSimulationConfigCompl + 
					Simulator.getInstance().getIntTotalChunksSent() + " 0 0" + "\n" );
		}


		System.out.println("## gerando DADOS_total_peers_poluidos e poluidos_CID: " + Util.sysdate2());

		// ----------------------------------------------
		// DADOS_total_peers_poluidos_SEG.txt
		// ----------------------------------------------
		String strPollutedPeersPerSecond = new String();
		int vTempTotal = 0;

		int totalPollutedChunks = 0;
		int totalOriginalChunks = 0;
		int totalChunksOriginalAndPolluted = 0;
		double pctTotalPollutedChunks;

		int totalPollutedChunksAfter30s = 0;
		int totalOriginalChunksAfter30s = 0;
		int totalChunksOriginalAndPollutedAfter30s = 0;
		double pctTotalPollutedChunksAfter30s;

		for ( int i = 0 ; i < (int)(Config.TIME + StreamingConfig.MCASTWINDOWSIZE); i++ ) {
			
			totalPollutedChunks += Simulator.getInstance().pollutedChunksPerSecond[i];
			totalOriginalChunks += Simulator.getInstance().originalChunksPerSecond[i];
			if (i >= 30 && i <= (int)Config.TIME ) {
				totalPollutedChunksAfter30s += Simulator.getInstance().pollutedChunksPerSecond[i];
				totalOriginalChunksAfter30s += Simulator.getInstance().originalChunksPerSecond[i];
			}

			vTempTotal = (Simulator.getInstance().pollutedChunksPerSecond[i] + Simulator.getInstance().originalChunksPerSecond[i]);
			if (vTempTotal == 0) { vTempTotal = 1; }
			
			strPollutedPeersPerSecond += strSimulationConfigCompl + Util.lpad( i, 4 ) + " " 
										+ Util.lpad( ""+Simulator.getInstance().pollutedPeersPerSecond[i]  ,5) + " " 
										+ Util.lpad( ""+Simulator.getInstance().pollutedChunksPerSecond[i] ,5) + " " 
										+ Util.lpad( ""+Simulator.getInstance().originalChunksPerSecond[i] ,5)  + " " 
										+ Util.lpad( ""+(Simulator.getInstance().pollutedChunksPerSecond[i] + Simulator.getInstance().originalChunksPerSecond[i])  ,5) + " " 
										+ Util.lpad( Util.to_char(   (((double)Simulator.getInstance().pollutedChunksPerSecond[i] * (double)100)/(double)vTempTotal)  ,2) , 10)
										+ "\n";
		}
		FileLog.getInstance().saveFinalStatsInFile("FinalStats", "DADOS_total_peers_poluidos_SEG", strPollutedPeersPerSecond);

		
		totalChunksOriginalAndPolluted = totalOriginalChunks + totalPollutedChunks;
		totalChunksOriginalAndPollutedAfter30s = totalOriginalChunksAfter30s + totalPollutedChunksAfter30s;
	


		// ----------------------------------------------
		// DADOS_total_peers_poluidos_CID.txt
		// ----------------------------------------------

					// - para TODOS os chunks, quantos peers receberam o conteudo diferente do original 
					// --> DADOS_total_peers_poluidos.txt 
				    // (1 linha p/ cada simulacao, ex.: "[5%,sempre,semch,200,15] #sim #qtde_media" )

		Double totalPolluted = 0.0;
		int totalPolluted_cid = 0;

		for (int cid = 0; cid <= (Config.TIME * StreamingConfig.MCASTRATE); cid++) {
			totalPolluted_cid = 0;
			totalPolluted_cid = Simulator.getInstance().getPollutedPeers().get(cid) != null ? Simulator.getInstance().getPollutedPeers().get(cid).size() : 0;
			totalPolluted += totalPolluted_cid;

			FileLog.getInstance().saveFinalStatsInFile( "FinalStats", "DADOS_total_peers_poluidos_CID", strSimulationConfigCompl + 
					Util.lpad(cid,4) + " " + Util.lpad( totalPolluted_cid, 4)  + "\n");
		}

		// ----------------------------------------------
		// DADOS_total_peers_poluidos.txt
		// ----------------------------------------------
		double avgPolluted = totalPolluted / (Config.TIME * StreamingConfig.MCASTRATE);
		
		pctTotalPollutedChunks = Util.trunc( (double)((double)totalPollutedChunks/(double)totalChunksOriginalAndPolluted*(double)100) , 2 );
		pctTotalPollutedChunksAfter30s = Util.trunc( (double)((double)totalPollutedChunksAfter30s/(double)totalChunksOriginalAndPollutedAfter30s*(double)100) , 2 );

		FileLog.getInstance().saveFinalStatsInFile( "FinalStats", "DADOS_total_peers_poluidos", strSimulationConfigCompl
				+ Util.trunc(avgPolluted,2) + "    "
				+ totalPollutedChunks + " "
				+ totalChunksOriginalAndPolluted + " "
				+ Util.lpad( Util.to_char( pctTotalPollutedChunks, 2), 6) + "    "
				+ totalPollutedChunksAfter30s + " "
				+ totalChunksOriginalAndPollutedAfter30s + " "
				+ Util.lpad( Util.to_char( pctTotalPollutedChunksAfter30s, 2), 6) + " "
				+ "\n");

		System.out.println("## fim geracao DADOS_total_peers_poluidos e poluidos_CID: " + Util.sysdate2());


		

		// ----------------------------------------------
		// DADOS_total_chunks_poluidos_SEG.txt
		// ----------------------------------------------
		// String strPollutedChunksPerSecond = new String();
		// for ( int i = 0 ; i < (int)(Config.TIME + StreamingConfig.MCASTWINDOWSIZE); i++ ) {
		// 	strPollutedChunksPerSecond += strSimulationConfig + numSim + " " + i + " " + Simulator.getInstance().pollutedChunksPerSecond[i] + "\n";
		// }
		// FileLog.getInstance().saveFinalStatsInFile("FinalStats", "DADOS_total_chunks_poluidos_SEG", strPollutedChunksPerSecond);

		

		// ----------------------------------------------
		// DADOS_acoes_blacklist.txt
		// ----------------------------------------------

		if (Config.USE_COMPARATOR_MODULE) {
			System.out.println( "## Inicio geracao --> DADOS_acoes_blacklist.txt: " + Util.sysdate2()  );
			// DADOS_acoes_blacklist.txt --> [cfg]    #id_simulacao   id_peer   qtde_vizinhos    qtde_vizinhos_poluidores   tempo_simulacao_update_blacklist
			//                                        foi_sobre_hash_correto?(Y/N)       qtde_total_blacklisted      qtde_vizinhos_poluidores_blacklisted

			Integer qtdeVizinhosPoluidoresCid = 0;
			String strMonitoredChunksBlacklistPeers = "";
			StringBuffer strMonitoredChunksBlacklistPeersSB = new StringBuffer();
			TreeSet<Blacklist> simulatorTotalBlacklisted = Simulator.getInstance().totalBlacklisted;
			System.out.println("## Simulator Blacklist size: "	+ simulatorTotalBlacklisted.size());
			System.out.println("## Simulator isAttacker size: " + Simulator.getInstance().isAttacker.length);
			System.out.println("## Simulator isPolluted: "	+ Simulator.getInstance().isPolluted.length);
			for (Blacklist blacklist : simulatorTotalBlacklisted) {

				Host i = blacklist.host;			

				qtdeVizinhosPoluidoresCid = 0;
				if (i != null && i.comparatorModule.chunksToBeCompared != null && i.comparatorModule.chunksToBeCompared.contains(blacklist.cid)){
						for (int k = 0; k < i.getNeighborIds().length; k++) {
							if (i.getNeighborIds()!=null && Simulator.getInstance().isAttacker[i.getNeighborIds()[k]]) {
								qtdeVizinhosPoluidoresCid++;
							}
						}

						int qtBlacklistedPolluter = 0;
						int hit = 0;
						if (blacklist.blacklistedIds != null) {
							for (Integer neighborId : blacklist.blacklistedIds) {
								if (Simulator.getInstance().isAttacker[neighborId]) {
									qtBlacklistedPolluter++;
								}
								if (Simulator.getInstance().isPolluted[blacklist.cid].contains(neighborId)) {
									hit++;
								}
							}
						}

						/*
						 * strMonitoredChunksBlacklistPeers += strSimulationConfig + numSim + " " + blacklist.cid + " " + i.getId() + " " +
						 * i.getNumberNeighbors() + " " + qtdeVizinhosPoluidoresCid + " " + blacklist.time + " " +
						 * (i.originalHashHit.get(blacklist.cid)!=null ? i.originalHashHit.get(blacklist.cid) : "0") + " " +
						 * (blacklist.blacklistedIds!=null ? blacklist.blacklistedIds.size() : 0) + " " +
						 * blacklist.blacklistedIds + " " + qtBlacklistedPolluter + " " + hit + "\n";
						 */

						strMonitoredChunksBlacklistPeersSB
								.append( strSimulationConfigCompl      ).append(" ")
								.append( Util.lpad( i.getId() ,4)      ).append(" ")
								.append( Util.lpad( blacklist.cid ,5)  ).append(" ")
								.append( Util.lpad( i.getNumberNeighbors(), 3)      ).append(" ")
								.append( Util.lpad( qtdeVizinhosPoluidoresCid, 3)   ).append("  ")
								.append( Util.lpad( Util.to_char(blacklist.time,2), 6)      ).append("  ")
								.append( (i.originalHashHit.get(blacklist.cid) != null ? i.originalHashHit.get(blacklist.cid) : "0")).append("  ")
								.append( Util.lpad( (blacklist.blacklistedIds != null ? blacklist.blacklistedIds.size() : 0) ,3)      ).append("  ")
								.append( Util.lpad( qtBlacklistedPolluter, 3 )      ).append("  ")
								.append( (i.strUSetsBlacklist.get(blacklist.cid) != null ? i.strUSetsBlacklist.get(blacklist.cid) : "0")).append("  ")
								.append( hit ).append("  ")
								.append( Util.rpad( (blacklist.blacklistedIds!=null ? blacklist.blacklistedIds.toString().replace(" ", "") : "")    ,40)        ).append(" ")
								.append("\n");

				}
			}

			System.out.println("## Writing DADOS_blacklist_CID... " + Util.sysdate2()  );
			FileLog.getInstance().saveFinalStatsInFile( "FinalStats", "DADOS_blacklist_CID", strMonitoredChunksBlacklistPeersSB.toString() );
			System.out.println("## Finalized DADOS_blacklist_CID... " + Util.sysdate2()  );

		}



		// ----------------------------------------------
		// OUTROS ARQUIVOS DE LOG COMENTADOS - NAO USADOS
		// ----------------------------------------------
		
		// String strChunksSentWithoutCMPerSecond = new String();
		// String strChunksSentByCMPerSecond = new String();
		// //String strUSetsSentPerSecond = new String();
		//
		// System.out.println("gerando DADOS_chunks-env-fireflies_SEG.txt: "+Util.sysdate2()  );
		//
		// for (int i = 0 ; i < (int)(Config.TIME +
		// StreamingConfig.MCASTWINDOWSIZE); i++){
		// /* 6 */ // - chunks/s enviados (reply) normalmente pelo Fireflies
		// (sem o MC) --> DADOS_chunks-env-fireflies_SEG.txt (1 linha p/ cada
		// simulacao/seg, ex.: [5%,sempre,semch,200,15] #sim seg qtde_chunks )
		// strChunksSentWithoutCMPerSecond += "["+ attackerRatio + "," +
		// polluterType + "," + churnUsed +"," +
		// StreamingConfig.INITIAL_HOSTS_NUMBER + "," +
		// (int)StreamingConfig.CHUNK_SELECTION_INTERVAL + "] " +
		// numSim + " " + i + " " +
		// Simulator.getInstance().chunksSentWithoutCMPerSecond[i] + "\n";
		//
		// /* 7 */ // - chunks/s enviados especificamente pelo MC (reply de um request do MC) --> DADOS_chunks-env-mod-comp_SEG.txt 
		// (1 linha p/ cada simulacao/seg, ex.: [5%,sempre,semch,200,15] #sim seg qtde_chunks )
		// strChunksSentByCMPerSecond += "["+ attackerRatio + "," + polluterType + "," + churnUsed +"," + StreamingConfig.INITIAL_HOSTS_NUMBER + "," + (int)StreamingConfig.CHUNK_SELECTION_INTERVAL + "] " +
		// numSim + " " + i + " " +
		// Simulator.getInstance().chunksSentByCMPerSecond[i] + "\n";
		// }
		//
		// System.out.println("fim geracao DADOS_chunks-env-fireflies_SEG.txt: "+Util.sysdate2()  );
		//
		// FileLog.getInstance().saveFinalStatsInFile("FinalStats","DADOS_chunks-env-fireflies_SEG", strChunksSentWithoutCMPerSecond); /* 6 save file*/
		// FileLog.getInstance().saveFinalStatsInFile("FinalStats","DADOS_chunks-env-mod-comp_SEG", strChunksSentByCMPerSecond); /* 7 save file */
		
		//String strPoluidosPorChunk = new String();
		//
		//for (int i = 0; i < ((StreamingConfig.MCASTRATE * Config.TIME) + 1); i++) {
		//	FileLog.getInstance().saveFinalStatsInFile(
		//			"FinalStats",
		//			"DADOS_poluidos_por_chunk",
		//			"[" + attackerRatio + "," + polluterType + "," + churnUsed
		//					+ "," + StreamingConfig.INITIAL_HOSTS_NUMBER + ","
		//					+ (int) StreamingConfig.CHUNK_SELECTION_INTERVAL
		//					+ "] " + numSim + " " + i + " "
		//					+ Simulator.getInstance().isPolluted[i].size()
		//					+ "\n");
		//}
		
		/* 3 */// - para cada peer/chunks monitorados salvar #vizinhos
				// #vizinhos_maliciosos, #diag_ok, #falso_positivo
				// #nao_responderam --> DADOS_peers-diag_completo.txt (1 linha
				// p/ cada simulacao/cid/???, ex.: [5%,sempre,semch,200] #sim
				// cid idpeer #vizinhos_naquele_momento #vizinhos_poluidores
				// #poluidores_diagnosticados_OK #vizinhos_diagnosticados_NOK
				// #peers_omissos )
		/*
		 * Integer qtdeVizinhosPoluidoresCid = 0; String
		 * strMonitoredChunksPollutedPeers = new String(); for ( Host i :
		 * Overlay.getInstance().getAllHosts() ) { for ( Integer cidsMonitorado
		 * : i.comparatorModule.chunksToBeCompared ) { String data = "Chunk " +
		 * cidsMonitorado + " original."; String notAnswered =
		 * "Haven't answered"; String hashDataNotPolluted =
		 * i.comparatorModule.generateHash(data);
		 * 
		 * Integer qtdeVizinhosPoluidoresDiagOk = 0; Integer
		 * qtdeVizinhosPoluidos = 0; Integer qtdeVizinhosNaoResponderam = 0;
		 * Integer intPollutedPeers = 0;
		 * 
		 * strMonitoredChunksPollutedPeers = "";
		 * 
		 * 
		 * //System.out.println("Host:" i.getId() "- CID -" cidsMonitorado);
		 * qtdeVizinhosPoluidoresCid = 0; RequestedPacket rPacket =
		 * i.comparatorModule.getRequestedPacketChunk(cidsMonitorado);
		 * if(rPacket != null) { for ( Integer k : rPacket.getNeighborsIdList())
		 * { // qtde de vizinhos do peer do loop (i) que estavam poluidos
		 * naquele momento da simulacao (no momento em que aquele chunk em
		 * questao cidsMonitorados estava na rede) // criar e zerar um array
		 * poluicaoNosPeers[chunk,[id_peers_poluidos1,2,3]] ja com
		 * segundos*chunks/s posicoes. // adicionar este valor no arquivao... e
		 * nao no aruqivo separado. // modificar o metodo handlePacket do
		 * host... ver comentario la // verificar dentro do array quantos
		 * vizinhos do peer atual estavam poluidos // o correto é o if abaixo,
		 * e nao esta linha logo abaixo: //Metodo errado //intPollutedPeers =
		 * (Simulator.getInstance().getPollutedPeers().get(cidsMonitorado) !=
		 * null) ?
		 * Simulator.getInstance().getPollutedPeers().get(cidsMonitorado).size()
		 * : -1;
		 * 
		 * //IMPLEMENTAR estas 2 linhas abaixo. if
		 * (Simulator.getInstance().isPolluted[cidsMonitorado].contains(k)) {
		 * intPollutedPeers++; }
		 * 
		 * if( Simulator.getInstance().isAttacker[k] == true ) {
		 * qtdeVizinhosPoluidoresCid++;
		 * 
		 * for (String hash : rPacket.getUSet().keySet()) { if
		 * (!hash.equalsIgnoreCase(hashDataNotPolluted) &&
		 * !hash.equalsIgnoreCase(notAnswered)) { for(HostRequestedDiagnostic
		 * hrd : rPacket.getUSet().get(hash)){ if (hrd.getHostId().equals(k))
		 * qtdeVizinhosPoluidoresDiagOk++; } } } }
		 * 
		 * for (String hash : rPacket.getUSet().keySet()) { if
		 * (!hash.equalsIgnoreCase(hashDataNotPolluted) &&
		 * !hash.equalsIgnoreCase(notAnswered)) { for(HostRequestedDiagnostic
		 * hrd : rPacket.getUSet().get(hash)){ if (hrd.getHostId().equals(k)) {
		 * qtdeVizinhosPoluidos++; } } } } }
		 * 
		 * if(rPacket.getUSet().get(notAnswered) != null) {
		 * qtdeVizinhosNaoResponderam =
		 * (rPacket.getUSet().get(notAnswered).size()); }
		 * 
		 * //ArrayList<Integer> HostIdList =
		 * i.comparatorModule.getHostIdListFromSetU(cidsMonitorado);
		 * //if(!rPacket.getNeighborsIdList()) { strMonitoredChunksPollutedPeers
		 * = "[" + attackerRatio + "," + polluterType + "," + churnUsed + "," +
		 * StreamingConfig.INITIAL_HOSTS_NUMBER + "," +
		 * (int)StreamingConfig.CHUNK_SELECTION_INTERVAL + "] " + numSim + " " +
		 * cidsMonitorado + " " + i.getId() + " " + rPacket.getNeighborsNumber()
		 * + " " + qtdeVizinhosPoluidoresCid + " " +
		 * qtdeVizinhosPoluidoresDiagOk + " " + qtdeVizinhosPoluidos + " " +
		 * qtdeVizinhosNaoResponderam + " " + intPollutedPeers + "\n";
		 * 
		 * //FileLog.getInstance().saveFinalStatsInFile("FinalStats",
		 * "DADOS_peers-diag-completo_CID", strMonitoredChunksPollutedPeers); }
		 * } } FileLog.getInstance().saveFinalStatsInFile(
		 * "DADOS_peers-diag-completo_CID", strMonitoredChunksPollutedPeers);
		 * for ( Host i : Overlay.getInstance().getAllHosts() ) { for ( Integer
		 * cidsMonitorado : i.comparatorModule.chunksToBeCompared ) { } }
		 */
		
		
		// -------------------------------------------------------------
		// FIM GERACAO ARQUIVOS DE LOG -- IMPRIMINDO ESTATISTICAS FINAIS
		// -------------------------------------------------------------

//		System.out.println("fim: " + Util.sysdate2()  );
//		System.out.println("msecs_blacklist " + Simulator.getInstance().msecs_blacklist);
//		System.out.println("msecs1 " + Simulator.getInstance().msecs1);
//		System.out.println("msecs2 " + Simulator.getInstance().msecs2);
//		System.out.println("msecs3 " + Simulator.getInstance().msecs3);
//		System.out.println("msecs4 " + Simulator.getInstance().msecs4);
//		System.out.println("msecs5 " + Simulator.getInstance().msecs5);
//		System.out.println("msecs6 " + Simulator.getInstance().msecs6);
//		System.out.println("msecs7 " + Simulator.getInstance().msecs7);
//		System.out.println("msecs8 " + Simulator.getInstance().msecs8);
//		System.out.println("total "+ (Simulator.getInstance().msecs1
//									  + Simulator.getInstance().msecs2
//									  + Simulator.getInstance().msecs3
//									  + Simulator.getInstance().msecs4
//									  + Simulator.getInstance().msecs5
//									  + Simulator.getInstance().msecs6
//									  + Simulator.getInstance().msecs7 
//									  + Simulator.getInstance().msecs8)
//							);
//		System.out.println("msecs_chunksToBeCompared: " + Simulator.getInstance().msecs_chunksToBeCompared);
//		System.out.println("chunksToBeComparedContains: " + Simulator.getInstance().chunksToBeComparedContains);

		// -------------------------------------------------------------
		
		chainsaw = null;
		Simulator simulator = Simulator.getInstance();
		Overlay.getInstance().resetOverlay();
		simulator.reset();
		Logs.printMessage( "main", "## Fim execucao " + (numSim) );

		FileLog.getInstance().closeFileLog();
		FileLog.getInstance().closeFileResults();
		FileLog.getInstance().closeFileParameters();
		FileLog.nullInstance();

		System.out.println("## [end] --> startSimulation " +"["+Util.to_char(startSimulationDate)+"]");
}
	// ----------------------
	// FIM -- startSimulation
	// ----------------------

	
	
	
	private static void setConfigurations(int i) {
		switch (i) {
		case 1:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.0;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 2:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.05;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 3:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.1;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 4:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.15;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 5:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.2;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 6:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.25;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 7:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.0;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 8:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.05;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 9:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.10;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 10:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.15;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 11:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.2;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 12:
			StreamingConfig.DYNAMIC_INSERTION_ON = false;
			StreamingConfig.DYNAMIC_REMOVAL_ON = false;
			StreamingConfig.ATTACKERS_RATIO = 0.25;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 13:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.0;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 14:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.05;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 15:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.10;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 16:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.15;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 17:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.20;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 18:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.25;
			StreamingConfig.ALWAYS_POLLUTE = true;
			break;
		case 19:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.0;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 20:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.05;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 21:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.10;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 22:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.15;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 23:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.20;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		case 24:
			StreamingConfig.DYNAMIC_INSERTION_ON = true;
			StreamingConfig.DYNAMIC_REMOVAL_ON = true;
			StreamingConfig.ATTACKERS_RATIO = 0.25;
			StreamingConfig.ALWAYS_POLLUTE = false;
			break;
		}
	}

	private void printPollutedPeers() {
		// //Implementar
	}

	public double meanPollutedInDiagnosed() {
		// //Implementar
		return 0.0;
	}

	public double diagnosticAccuracy() {
		// //Implementar
		return 0.0;
	}


	// -------------------------------------------------
	// EXPERIMENT WITHOUT ATTACKERS
	// -------------------------------------------------
	
	public void experimentWithoutAttackers(int numSim) {

		Simulator simulator = Simulator.getInstance();
		TopologyGenerator.firefliesTopology( StreamingConfig.INITIAL_HOSTS_NUMBER, Config.RING_NUM );

		System.out.println("## Simulation without attackers.");

		periodicStats.addEvent();
		((SourceHost) overlay.getHost(0)).propagate();

		
		simulator.run(numSim);

		
		Object[] hostsList = overlay.hosts.values().toArray();

		Arrays.sort(hostsList, new idComparator());

		//int media = 0;
		for (int i = 0; i < hostsList.length; i++) {
			Host auxHost = (Host) hostsList[i];

			// Check if the host has data not added to download and upload stats
			// variables
			if (auxHost.receivedCount > 0) {
				auxHost.downloadStats.add(auxHost.receivedCount);
			}

			if (auxHost.sentCount > 0) {
				auxHost.uploadStats.add(auxHost.sentCount);
			}

			auxHost.printStats();
		}

		periodicStats.stop();
		// simulator.reset();
	}

	public void allAttacks(int numSim) {
		for (double i = 0.05; i <= 0.25; i += 0.05) {
			System.out.println("Attack type 1 -- p = " + i);
			experimentWithAttackers(1, i, numSim);
		}
	}

	
	// -------------------------------------------------
	// EXPERIMENT WITH ATTACKERS
	// -------------------------------------------------

	public void experimentWithAttackers(int attackType, double ratioAttackers, int numSim) {

		System.out.println("## [ini] --> experimentWithAttackers");

		Simulator simulator = Simulator.getInstance();

		int numberByz = (int) Math.round(ratioAttackers
				* StreamingConfig.INITIAL_HOSTS_NUMBER); // Number of peers with
															// byzantine
															// beahavior
		int numReps = 1; // Number of repetitions

		// Vector to the experiments data acquisition
		double minDownload[] = new double[numReps];
		double avgDownload[] = new double[numReps];
		double maxDownload[] = new double[numReps];
		double minUpload[] = new double[numReps];
		double avgUpload[] = new double[numReps];
		double maxUpload[] = new double[numReps];
		int goodNodesLost = 0;

		for (int j = 0; j < numReps; j++) {
			TopologyGenerator.firefliesByzTopology(
					StreamingConfig.INITIAL_HOSTS_NUMBER, Config.RING_NUM,
					attackType, ratioAttackers);
			periodicStats.addEvent();
			((SourceHost) overlay.getHost(0)).propagate();
			int onePolluter = 0;
			String msg = "Polluters at begining of simulation: ";
			for (int i = 0; i < StreamingConfig.INITIAL_HOSTS_NUMBER; i++) {
				if (simulator.isAttacker[i]) {
					msg += i + ",";
					if (onePolluter == 0) {
						onePolluter = i;
					}
				}
			}
			Logs.printMessage("main", msg);

			
			// ----------------------------------------------
			// get one polluter neighbor to monitor logs...
			// ----------------------------------------------
			int onePolluterNeighbor = 0;
			for (int i = 0; i < StreamingConfig.INITIAL_HOSTS_NUMBER; i++) {
				Host h = Overlay.getInstance().getHost(i);
				for (int k = 0; k < h.getNeighborIds().length; k++) {
					// ALTERAR AQUI (LOGAR OU NAO VIZINHO DO PEER 0)
					if ( onePolluterNeighbor == 0 && i==onePolluter){
					//if (onePolluterNeighbor == 0 && i == 0) {
						onePolluterNeighbor = h.getNeighborIds()[k];
					}
				}
			}
			Logs.onePolluterNeighbor = onePolluterNeighbor;
			// ----------------------------------------------


			simulator.run(numSim);

			/* Do the measures based on data acquired from simulation */
			Host host;

			Statistics downloadStats = new FullStatistics();
			Statistics uploadStats = new FullStatistics();
			for (int i = 1; i < (StreamingConfig.INITIAL_HOSTS_NUMBER - numberByz); i++) {
				host = overlay.getHost(i);
				if (host != null) {
					downloadStats.add(host.downloadStats.avg());
					uploadStats.add(host.uploadStats.avg());
				} else {
					goodNodesLost++;
				}
			}

			avgDownload[j] = downloadStats.avg();
			minDownload[j] = downloadStats.min();
			maxDownload[j] = downloadStats.max();
			avgUpload[j] = uploadStats.avg();
			minUpload[j] = uploadStats.min();
			maxUpload[j] = uploadStats.max();

			periodicStats.stop();

			// simulator.reset();
		}
		double r = StreamingConfig.MCASTRATE;

		try {
			PrintStream out = new PrintStream(new FileOutputStream(filename
					+ "Down.rates"));
			for (int i = 0; i < avgDownload.length; i++) {
				out.println(avgDownload[i] / r + " " + minDownload[i] / r + " "
						+ maxDownload[i] / r);
			}
			out.close();
			out = new PrintStream(new FileOutputStream(filename + "Up.rates"));
			for (int i = 0; i < avgDownload.length; i++) {
				out.println(avgUpload[i] / r + " " + minUpload[i] / r + " "
						+ maxUpload[i] / r);
			}
			out.close();
		} catch (Exception e) {
			System.out.println("Problems writing output to file");
		}
		Arrays.sort(avgDownload);
		Arrays.sort(minDownload);
		Arrays.sort(maxDownload);
		Arrays.sort(avgUpload);
		Arrays.sort(minUpload);
		Arrays.sort(maxUpload);

		int index5 = (int) (0.05 * avgDownload.length) - 1;
		int median = (int) (0.5 * avgDownload.length) - 1;
		int index95 = (int) (0.95 * avgDownload.length) - 1;

		// System.out.println(" hello " + index5 + " " + median + " " +
		// index95);

		if (index5 == -1)
			index5 = 0;
		if (median == -1)
			median = 0;
		if (index95 == -1)
			index95 = 0;

		/*
		 * System.out.println("Minimum Download: "); System.out.println("5% - "
		 * + minDownload[index5] / r + " | " + "Median - " + minDownload[median]
		 * / r + " | " + "95% - " + minDownload[index95] / r + "\n");
		 * 
		 * System.out.println("Average Download: "); System.out.println("5% - "
		 * + avgDownload[index5] / r + " | " + "Median - " + avgDownload[median]
		 * / r + " | " + "95% - " + avgDownload[index95] / r + "\n");
		 * 
		 * System.out.println("Maximum Download: "); System.out.println("5% - "
		 * + maxDownload[index5] / r + " | " + "Median - " + maxDownload[median]
		 * / r + " | " + "95% - " + maxDownload[index95] / r + "\n");
		 * 
		 * 
		 * System.out.println("Minimum Upload: "); System.out.println("5% - " +
		 * minUpload[index5] / r + " | " + "Median - " + minUpload[median] / r +
		 * " | " + "95% - " + minUpload[index95] / r + "\n");
		 * 
		 * System.out.println("Average Upload: "); System.out.println("5% - " +
		 * avgUpload[index5] / r + " | " + "Median - " + avgUpload[median] / r +
		 * " | " + "95% - " + avgUpload[index95] / r + "\n");
		 * 
		 * System.out.println("Maximum Upload: "); System.out.println("5% - " +
		 * maxUpload[index5] / r + " | " + "Median - " + maxUpload[median] / r +
		 * " | " + "95% - " + maxUpload[index95] / r + "\n");
		 */
		System.out.println("## [end] --> experimentWithAttackers");
	}

	public class idComparator implements Comparator {

		public int compare(Object arg0, Object arg1) {
			Host h1 = (Host) arg0;
			Host h2 = (Host) arg1;

			if (h1.getId() > h2.getId()) {
				return 1;
			} else if (h1.getId() > h2.getId()) {
				return -1;
			} else {
				return 0;
			}
		}

	}


}
